package com.example.pcl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.pcl.constant.MessageConstants;
import com.example.pcl.exception.ObjectException;
import com.example.pcl.mapper.*;
import com.example.pcl.pojo.dto.AppointmentDto;
import com.example.pcl.pojo.dto.AppointmentQueryDto;
import com.example.pcl.pojo.dto.AppointmentStatusDTO;
import com.example.pcl.pojo.dto.BatchCancelDto;
import com.example.pcl.pojo.entity.Appointments;
import com.example.pcl.pojo.entity.ConsultationRecords;
import com.example.pcl.pojo.entity.Counselors;
import com.example.pcl.pojo.entity.Notifications;
import com.example.pcl.pojo.vo.AppointmentVo;
import com.example.pcl.result.PageResult;
import com.example.pcl.service.IAppointmentsService;
import com.example.pcl.utils.ThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 预约表，记录学生与心理咨询师的预约信息 服务实现类
 * </p>
 *
 * @author xx
 * @since 2024-12-17
 */
@Service
@RequiredArgsConstructor
public class AppointmentsServiceImpl extends ServiceImpl<AppointmentsMapper, Appointments> implements IAppointmentsService {
    private final UsersMapper usersMapper;
    private final ConsultationRecordsMapper consultationRecordsMapper;
    private final NotificationsMapper notificationsMapper;
    private final CounselorsMapper counselorsMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAppointment(@NotNull AppointmentDto appointmentDto) {
        Integer userId = ThreadLocalUtil.getId();
        if (StringUtils.isEmpty(usersMapper.selectById(userId).getPhone())) {
            throw new ObjectException("用户联系方式为空不允许预约");
        }
        List<Appointments> list = list(new LambdaQueryWrapper<Appointments>()
                .eq(Appointments::getUserId, userId)
                .in(Appointments::getStatus, Appointments.TO_BE_CONFIRMED, Appointments.CONFIRMED));
        if (CollectionUtil.isNotEmpty(list)) {
            throw new ObjectException("您有预约还为完成。");
        }
        Integer counselorId = appointmentDto.getCounselorId();
        Counselors counselors = counselorsMapper.selectById(counselorId);

        if (counselors == null) {
            throw new ObjectException("心理咨询师不存在");
        }
        Appointments appointment = Appointments.builder()
                .userId(userId)
                .counselorId(counselorId)
                .appointmentTime(appointmentDto.getAppointmentTime())
                .statusDescription("预约成功，待心理咨询师确认")
                .appointmentMethod(appointmentDto.getAppointmentMethod())
                .status(Appointments.TO_BE_CONFIRMED).build();
        int result = baseMapper.insert(appointment);
        notificationsMapper.insert(new Notifications()
                .setRecipientId(counselors.getUserId())
                .setAppointmentId(appointment.getAppointmentId())
                .setTitle("新的心理咨询预约")
                .setContent("用户预约了，请您尽快确认哦")
                .setNotificationStatus(Notifications.UNREAD)
                .setExpirationTime(LocalDateTime.now().plusDays(1).toLocalDate().atStartOfDay()));
        if (result < 0) {
            throw new RuntimeException("预约创建失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAppointmentStatus(@NotNull AppointmentStatusDTO statusDTO) {
        Integer appointmentId = statusDTO.getAppointmentId();
        String statusDescription = statusDTO.getStatusDescription();
        Integer status = statusDTO.getStatus();

        // 查询预约信息
        Appointments appointment = baseMapper.selectById(appointmentId);
        if (appointment == null) {
            throw new RuntimeException("预约不存在，ID：" + appointmentId);
        }

        // 获取当前预约状态
        Integer currentStatus = appointment.getStatus();

        // 判断状态变化的情况
        if (Objects.equals(currentStatus, Appointments.TO_BE_CONFIRMED) &&
                Objects.equals(status, Appointments.CONFIRMED)) {  // 待确认 -> 已确认
            // 插入咨询记录
            insertConsultationRecord(appointmentId, appointment.getCounselorId(), appointment.getUserId());

            // 发送已确认的通知
            sendNotification(appointment, "心理咨询预约进度",
                    "心理咨询师已确认请你在规定时间到达地点进行咨询");

        } else if (Objects.equals(currentStatus, Appointments.TO_BE_CONFIRMED) &&
                Objects.equals(status, Appointments.CANCELLED)) {
            // 删除咨询记录
            deleteConsultationRecord(appointmentId);
            notificationsMapper.delete(new LambdaUpdateWrapper<Notifications>().eq(Notifications::getAppointmentId, appointmentId));
        } else if (Objects.equals(currentStatus, Appointments.CONFIRMED) &&
                (Objects.equals(status, Appointments.TO_BE_CONFIRMED) ||
                        Objects.equals(status, Appointments.CANCELLED))) {  // 已确认 -> 待确认 或 已取消
            // 删除咨询记录
            deleteConsultationRecord(appointmentId);
            notificationsMapper.delete(new LambdaUpdateWrapper<Notifications>().eq(Notifications::getAppointmentId, appointmentId));
        } else if (Objects.equals(currentStatus, Appointments.CONFIRMED) &&
                Objects.equals(status, Appointments.COMPLETED)) {  // 已确认 -> 已完成
            // 发送已完成的通知
            sendNotification(appointment, "心理咨询预约完成", "您的心理咨询预约已完成，感谢您的预约！");
        }

        // 更新预约状态和状态说明
        appointment.setStatus(status);
        appointment.setStatusDescription(statusDescription);

        // 执行更新操作
        int result = baseMapper.updateById(appointment);
        if (result < 0) {
            throw new RuntimeException("预约状态更新失败");
        }
    }

    @Override
    public void updateAppointment(@NotNull AppointmentDto appointmentDto) {
        // 根据预约ID获取当前预约记录
        Appointments appointment = baseMapper.selectById(appointmentDto.getAppointmentId());

        if (appointment == null) {
            throw new RuntimeException("预约记录不存在，ID：" + appointmentDto.getAppointmentId());
        }

        // 检查预约状态，如果是已取消或已完成，不能修改
        if (Objects.equals(appointment.getStatus(), Appointments.CANCELLED) ||
                Objects.equals(appointment.getStatus(), Appointments.COMPLETED)) {
            throw new RuntimeException("已取消或已完成的预约无法修改");
        }

        // 如果是待确认或已确认状态，则允许修改
        if (Objects.equals(appointment.getStatus(), Appointments.TO_BE_CONFIRMED) ||
                Objects.equals(appointment.getStatus(), Appointments.CONFIRMED)) {
            // 更新预约信息
            appointment.setUserId(appointmentDto.getUserId())
                    .setCounselorId(appointmentDto.getCounselorId())
                    .setAppointmentTime(appointmentDto.getAppointmentTime())
                    .setStatusDescription(appointmentDto.getStatusDescription())
                    .setAppointmentMethod(appointmentDto.getAppointmentMethod());


            int result = baseMapper.updateById(appointment);

            if (result < 1) {
                throw new RuntimeException("预约更新失败");
            }
        } else {
            throw new RuntimeException("无法修改此状态的预约");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCancelAppointments(@NotNull BatchCancelDto cancelDto) {
        List<Appointments> appointments = baseMapper.selectList(new LambdaQueryWrapper<Appointments>()
                .in(Appointments::getAppointmentId, cancelDto.getAppointmentIds()));
        if (appointments.isEmpty()) {
            throw new RuntimeException("未找到对应的预约记录");
        }
        for (Appointments appointment : appointments) {
            appointment.setStatus(Appointments.CANCELLED);
            appointment.setStatusDescription(cancelDto.getStatusDescription());
            baseMapper.updateById(appointment);
            deleteConsultationRecord(appointment.getAppointmentId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAppointment(Integer appointmentId) {
        // 查询预约信息
        Appointments appointment = getById(appointmentId);
        if (appointment == null) {
            throw new ObjectException("预约信息不存在，请检查");
        }

        // 如果预约状态为已确认，不允许删除
        if (appointment.getStatus() != null && appointment.getStatus().equals(Appointments.CONFIRMED)) {
            throw new ObjectException("已确认的预约不能删除");
        }
        deleteConsultationRecord(appointmentId);
        if (!removeById(appointmentId)) {
            throw new ObjectException("删除失败，请重试");
        }
    }

    @Override
    public AppointmentVo getAppointmentDetail(Integer appointmentId) {
        AppointmentVo vo = baseMapper.finById(appointmentId);
        if (vo == null) {
            throw new ObjectException("预约记录不存在");
        }
        return vo;
    }

    @Override
    public PageResult<AppointmentVo> getAppointmentList(@NotNull AppointmentQueryDto queryDto) {
        IPage<AppointmentVo> appointmentVoIPage = baseMapper.pageList(new Page<>(queryDto.getPageNum(), queryDto.getPageSize()), queryDto);
        return new PageResult<>(appointmentVoIPage.getTotal(), appointmentVoIPage.getRecords());
    }

    // 插入咨询记录方法
    private void insertConsultationRecord(Integer appointmentId, Integer counselorId, Integer userId) {
        // 创建咨询记录对象
        ConsultationRecords consultationRecord = new ConsultationRecords();
        consultationRecord.setAppointmentId(appointmentId)
                .setConsultationContent(MessageConstants.PLEASE_WAIT)
                .setSuggestions(MessageConstants.PLEASE_WAIT)
                .setUserId(userId)
                .setProblemAnalysis(MessageConstants.PLEASE_WAIT).setCounselorId(counselorId);
        // 插入数据到咨询记录表
        int insert = consultationRecordsMapper.insert(consultationRecord);
        if (insert < 0) {
            throw new ObjectException(MessageConstants.ADD_ERR);
        }
    }

    // 删除咨询记录方法
    private void deleteConsultationRecord(Integer appointmentId) {
        if (consultationRecordsMapper.selectOne(new LambdaQueryWrapper<ConsultationRecords>().eq(ConsultationRecords::getAppointmentId, appointmentId)) == null) {
            return;
        }
        // 删除对应的咨询记录
        int delete = consultationRecordsMapper.delete(new LambdaUpdateWrapper<ConsultationRecords>().eq(ConsultationRecords::getAppointmentId, appointmentId));
        if (delete < 0) {
            throw new ObjectException("咨询记录删除失败请重试");
        }
    }


    /**
     * 发送通知的通用方法
     *
     * @param appointment 预约信息
     * @param title       通知标题
     * @param content     通知内容
     */
    private void sendNotification(@NotNull Appointments appointment, String title, String content) {
        String[] timeParts = appointment.getAppointmentTime().split(" ");
        String date = timeParts[0];
        String[] timeRange = timeParts[1].split("-");
        String endTime = timeRange[1];
        LocalDateTime expirationTime = LocalDateTime.parse(date + " " + endTime + ":00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        notificationsMapper.insert(new Notifications()
                .setRecipientId(appointment.getUserId())
                .setAppointmentId(appointment.getAppointmentId())
                .setTitle(title)
                .setContent(content)
                .setNotificationStatus(Notifications.UNREAD)
                .setExpirationTime(expirationTime));
    }
}
